# -*- coding: utf-8 -*-

#
# fusion.http.Admin
#
# Copyright 2008 Helsinki Institute for Information Technology
# and the authors.
#
# Authors: Harri Hämäläinen <hhamalai@iki.fi>
#

# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from fusion.db.profile import Profile
from fusion.http.FusionApp import FusionApp, Response, invitations
from fusion.http.util import escape_html
from string import Template
import cgi, simplejson
import fusion.http.wsgiserver
import urllib

class Admin(FusionApp):
    def do_GET(self):
        host_info = fusion.http.wsgiserver.host_endpoint()

        if self.environ.get('HTTP_HOST').split(':')[0] == host_info[0] or \
                         self.environ.get('HTTP_HOST') == host_info[0]:
            response = Response()
            response.add_header('Content-Type', 'text/html;charset=utf-8')
            response.append_output(self.output_proxy_guide(host_info[0], host_info[1]))
            return response
        
        response = Response()
        
        try:
            iid = self.db.get_my_iid()
            self.db.fetch(iid, '')
        except LookupError: # persona not initialized
            return self.output_setup_persona()
    
        if self.environ.get('SCRIPT_NAME') == '/pending_invitation':
            content = ''
            if len(invitations) == 0:
                content = 'No pending invitations'
            else:
                content = self.output_pending_invitation()
            response.add_header('Content-Type', 'text/html;charset=utf-8')
            response.append_output(self.create_page('Pending invitations', content))

        elif self.environ.get('SCRIPT_NAME') == '/create_invitation':
            content = self.output_create_invitation()
            response.append_output(self.create_page('Create invitation', content))
        
        elif self.environ.get('SCRIPT_NAME') == '/create_personal_code':
            content = self.output_create_personal_code()
            response.add_header('Content-Type', 'text/html;charset=utf-8')
            response.append_output(self.create_page('Create personal code', content))
            
        elif self.environ.get('SCRIPT_NAME') == '/browse':
            target = self.querydict.get('target')
            if not target:
                target = []
            content = self.output_browse(target)
            response.add_header('Content-Type', 'text/html;charset=utf-8')
            response.append_output(self.create_page('Browse', content))
            
        else:
            response = Response(500)

        return response


    def do_POST(self):
        global invitations
        response = Response()
        
        form = self.read_request_form()
        
        try:
            # Check if persona initialized and name specified. If not db.get_my_iid()
            # will throw LookupError
            self.db.get_my_iid()

        except LookupError:
            self.setup_persona(form)
            self.db.fetch(self.db.get_my_iid(), '')
            response = Response(301)
            response.add_header('Location', self.request_url())
            return response

            
        if form.getvalue("create_invitation"):
            code = self.db.create_friendship_invitation_code()
            if code:
                content = self.output_create_invitation('Single-use invitation code: ' + code + ' (<a href="mailto:' + str(escape_html(form.getvalue('email'))) + '?subject=Fusion Invitation&body=' + urllib.quote('''
                
This is an invitation to connect as friends in P2P-Fusion.

Information about the software is available here:

    http://hiit.fi/fusion/

With the software running on your computer, enter the
following invitation code:

    ''' + code + '''

Alternatively, simply click on the following link:

    http://hexlabel.net/?invitation_code='''+code+'''

    -''') + str(escape_html(self.db.get_text(self.db.get_my_iid(), '/public/name.txt')).encode('utf-8'))
                
                
                 + '">e-mail this</a>)')

                response.append_output(self.create_page('Create invitation', content))
            else:
                content = self.output_create_invitation('''Connection error, try again.''')
                response.append_output(self.create_page('Create invitation', content))
        
        elif form.getvalue('get_invitation'):
            result = self.invitation(form)
            if result:
                response = result
            else:
                response = self.do_GET()
        
        elif form.getvalue('delete_invitation'):
            global invitations
            invitations.clear()
            response = self.do_GET()
        
        elif form.getvalue('create_personal_code'):
            passphrase = form.getvalue("passphrase")
            if passphrase != form.getvalue("passphrase_confirm"):
                self.add_notification('''Passphrase given didn\'t match with 
                the confirmation''',
                target='create_personal_code')
                response = self.do_GET()
            
            elif not passphrase:
                self.add_notification('''Passphrase cannot be empty''',
                                      target='create_personal_code')
                response = self.do_GET()
            
            else:
                code = self.db.reset_personal_code(passphrase)
                response = Response()
                content = '''Your personal code is: %s<br />Keep it safe with 
                your chosen passphrase to import your details into other 
                systems in future''' % code
                response.add_header('Content-Type', 'text/html;charset=utf-8')
                response.append_output(self.create_page('Create personal code',  content))
        

        
        else:
            response = Response(500)
        
        return response

        
    def setup_persona(self, form):
        if form.getvalue('create_persona'):
            user_name = form.getvalue('user_name')
            iid = self.db.create_persona()
            profile = Profile()
            profile.name = user_name
            profile.write(self.db, iid)
            return iid
        
        elif form.getvalue('import_persona'):
            passphrase = form.getvalue('passphrase')
            code = form.getvalue('code')
            try:
                self.db.set_persona_from_code(code, passphrase)
                return True
            except LookupError:
                self.add_notification('''No such account. Probably you haven't used
                        Fusion within one week, or you misstyped your
                        passphrase/personal code''',
                        target='new_user')
            except:
                self.add_notification('''Failed to connect. Check connection and try again''',
                                      target='new_user')
 

    
    def output_pending_invitation(self):
        name = ''
        iid = ''
        type = None
        for iid, invitation in invitations.items():
            name = escape_html(self.db.get_text(iid, '/public/name.txt') or '').encode('utf-8')
            type = self.db.get_info(iid).get('type')
            
        if not 'show_delete' in self.querydict:
            if not name and type == 'person':
                name = 'somebody'
            elif not name and type == 'group':
                name = 'some group'
            return Template('''<div id="accept_invitation_field">
            This is an invitation from 
            <a href="http://${iid}.hexlabel.net">${name}</a>
            </div>
            ''').substitute(iid = iid, name = name or 'somebody')
            
        else:
            return Template('''<div id="accept_invitation_field">
            The <a href="http://${iid}.hexlabel.net">profile</a>
            to which this invitation refers is still unavailable.
            If you wish, you can delete the invitation.
            <form method="POST" action="">
            <!--<input type="button" value="Keep trying" onClick="history.go(-1)" />-->
            <input type="submit" name="delete_invitation" value="Delete" />
            </form>
            </div>
            ''').substitute(iid = iid, name = name)

    
    def output_browse(self, expanded):
        def join_paragraphs(domcells, contcells):
            assert len(domcells) > 0

            num_domcells = len(domcells) + 1
            output = '''<table><tr>%s<td class="browse_content" rowspan="%s">%s</td></tr>
                     ''' % (domcells.pop(0), num_domcells, ''.join(contcells))
            
            for dom in domcells:
                style = style_closed
                if dom in expanded:
                    style = style_open
                output += '<tr>%s</tr>' % (dom)
            
            output += '<tr><td></td></tr></table>'
            return output
                
        me = self.db.get_my_iid()
        domains = [me]
        # Profile.py does not support groups yet 
        domains.extend(self.db.list_groups()) 
        persons = self.db.list_persons()
        persons.remove(me)
        domains.extend(persons)
        
        domain_links = []
        content_links = []
        
        style_closed = 'target closed'
        style_open = 'target open'
        
        for iid in domains:
            name = ''
            if self.db.fetch(iid, '', type='json')['type'] == 'person':
                profile = Profile()
                profile.read(self.db, iid)
                name = profile.name
            elif self.db.fetch(iid, '', type='json')['type'] == 'group':
                name = self.db.get(iid,'info/name.txt')
            else:
                name = self.db.get(iid, 'info/title.txt')
            pic_url = 'http://admin.hexlabel.net/static/dummy.png'
            if profile.pic:
                pic_url = 'http://%s.hexlabel.net/content/%s' % (iid, profile.pic_path)
            
            content_datasets = self.db.list_content(iid)
            
            domain_size = sum([self.db.get_size(iid, x) for x in self.db.keys(iid)])
            for ciid in content_datasets:
                domain_size += sum([self.db.get_size(ciid, x) for x in self.db.keys(ciid)])
            
            if iid in expanded:
                for ciid in content_datasets:
                    content_links.append('''<a style="position: top;" href="http://%s.hexlabel.net/presentation/web/index.html">%s</a><br />
                                         ''' % (ciid, escape_html(self.db.get(ciid, 'info/title.txt')) or iid[:20])) 
            style = style_closed
            if iid in expanded:
                style = style_open
            domain_links.append('''<td class="%s"><a href="/browse?target=%s">
                                <div><img style="max-width:50px;max-height:50px;" src="%s" />
                                %s<br />%.3f MB stored</div></a></td>
                                ''' % (style, iid, pic_url, escape_html(name) or iid[:20], domain_size / 1000000.0))
                                
        return join_paragraphs(domain_links, content_links).encode('utf-8')
        
        

    def output_create_invitation(self, result=''):
        return '''<div>
                Create an invitation for your friend.<br /><br />

                <form action="" method="POST">
                Friend's e-mail address (recommended):<br />
                <input type="text" name="email" /><br /><br />

                <input type="submit" name="create_invitation" 
                        value="Invite Friend" />
                </form>
                <div id="create_invitation_result">
                %s
                </div>
            </div>''' % result


    def output_create_personal_code(self):
        values = self.get_notifications('create_personal_code')
        notifications = '<ul>%s</ul>' % ''.join(['<li>%s</li>' % s 
                                                 for s 
                                                 in values])
                                                 
        return Template('''<div>
        <div>
        ${notifications}
        </div>
        <form action="" method="POST">
            Enter passphrase of your choice:
                <input type="password" name="passphrase" /><br />
            Retype the same passphrase:
                <input type="password" name="passphrase_confirm" /><br />
            <input type="submit" name="create_personal_code" value="Go" />
        </form>
        </div>
        ''').substitute(notifications = notifications)
    
    def output_setup_persona(self):
        response = Response()
        response.add_header('Content-Type', 'text/html;charset=utf-8')
        T_view = Template('''\
        <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
          <link type="text/css" href="/static/css/askname.css" rel="stylesheet" 
          title="Fusion Welcome">
          <link type="text/css" href="/static/css/main.css" rel="stylesheet" 
          title="Fusion Default">
          <title>Welcome to Fusion</title>
          <style>
        .safetycolor
        {
            border-color: ${safetycolor};
            color: #000;
        }
          </style>
        </head>
        <body>
          <h1>Welcome to Fusion</h1>
          <form method="post" action="" target="_top" >
            <div class="inputframe safetycolor">
              ${notifications}
              ${inputtype}
            </div>
          </form>
        </body></html>''')
        inputtype = '''
            <p>
            Enter your name to get going:<br />
            <input name="user_name"      id="user_name" type="text" />
            <input name="create_persona" id="create_persona" value="Go" 
            type="submit"/>
            </p><p>
            <a href="/?import_persona=T">already using Fusion?</a>
            </p>
            '''
        if 'import_persona' in self.querydict:
            inputtype = '''
            <p>
            Enter your passphrase and personal code:
            <center>
            <table>
            <tr><th>
            code:
            </th><td>
            <input name="code"      id="code" type="text" />
            </td></tr>
            <tr><th>
            passphrase:
            </th><td> 
            <input name="passphrase"      id="passphrase" type="text" />
            </td></tr>
            </table>
            </center>
            <div class="buttons">
            <input name="import_persona" id="import_persona" value="go" 
            type="submit"/>
            </div>
            </p><p>
            <a href="/?">new user?</a>
            </p> 
            '''
        
        response.append_output(T_view.substitute(safetycolor = self.db.get_safety_color(),
                                                 inputtype = inputtype,
                                                 notifications = self._get_notifications(target='new_user')))
        return response



    def output_proxy_guide(self, host, port):
        return'''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml">
        <head>
            <title>Fusion - Home</title>
            <link type="text/css" href="/static/css/proxyhelp.css" 
            rel="stylesheet" title="Fusion Front Door">
            <link type="text/css" href="/static/css/main.css" 
            rel="stylesheet" title="Fusion Default">

        </head>
        <body>
	    <h1><img src="/static/biglogo.png" alt="P2P-Fusion" /><br />
	     semantic<br /> overlay</h1>
    	<p class="important">
    	<a href="http://my.hexlabel.net/?"> enter </a></p>
    	</p>
            <p>
	    (On error, change proxy configuration URL to
            "<span style="font-family: monospace;">http://%s:%s/proxy.pac</span>".)
            </p>

        </body>
        </html>
        ''' % (host, port)
